package com.example.yin.service.impl;

import com.example.yin.dao.SimilarityMapper;
import com.example.yin.dao.SongtagMapper;
import com.example.yin.domain.Similarity;
import com.example.yin.service.SongSimilarityCalculatorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SongSimilarityCalculatorServiceImpl implements SongSimilarityCalculatorService {
    @Autowired
    private SongtagMapper songtagMapper;

    @Autowired
    private SimilarityMapper similarityMapper;

    @Override
    public void calculateAndStoreSimilarities() {
        // 获取所有歌曲的标签
        Map<Integer, Set<Integer>> songTags = getSongTags();

        // 计算所有歌曲之间的相似度
        Map<Pair<Integer, Integer>, Double> similarities = calculateSimilarities(songTags);

        // 将相似度结果存入数据库
        storeSimilarities(similarities);
    }

    @Override
    public Map<Integer, Set<Integer>> getSongTags(){
        Map<Integer, Set<Integer>> songTags = new HashMap<>();
        List<Integer> songIds = songtagMapper.getAllsongId();
        for(Integer songId :songIds){
            Set<Integer> tags = songtagMapper.getTagsbysongId(songId).stream().collect(Collectors.toSet());
            songTags.put(songId,tags);
        }
        return songTags;
    }

    @Override
    public Map<Pair<Integer, Integer>, Double> calculateSimilarities(Map<Integer, Set<Integer>> songTags) {
        Map<Pair<Integer, Integer>, Double> similarities = new HashMap<>();
        for (Map.Entry<Integer, Set<Integer>> entry1 : songTags.entrySet()) {
            for (Map.Entry<Integer, Set<Integer>> entry2 : songTags.entrySet()) {
                if (entry1.getKey() < entry2.getKey()) {
                    double similarity = cosineSimilarity(entry1.getValue(), entry2.getValue());
                    similarities.put(Pair.of(entry1.getKey(), entry2.getKey()), similarity);
                }
            }
        }
        return similarities;
    }

    @Override
    public double cosineSimilarity(Set<Integer> tags1, Set<Integer> tags2) {
        Set<Integer> intersection = new HashSet<>(tags1);
        intersection.retainAll(tags2);
        double numerator = intersection.size();
        double denominator = Math.sqrt(tags1.size()) * Math.sqrt(tags2.size());
        return numerator / denominator;
    }

    @Override
    public void storeSimilarities(Map<Pair<Integer, Integer>, Double> similarities)  {

        for (Map.Entry<Pair<Integer, Integer>, Double> entry : similarities.entrySet()) {

            Similarity similarity = new Similarity();
            similarity.setSongaId(entry.getKey().getFirst());
            similarity.setSongbId(entry.getKey().getSecond());
            similarity.setSimilarity(entry.getValue());
            similarityMapper.insert(similarity);

            //ystem.out.println(entry.getKey().getFirst()+" "+entry.getKey().getSecond()+" "+entry.getValue());
        }

    }

    @Override
    public void caculateSingle(Integer songId, List<Integer> tags){

        Set<Integer> tgs = tags.stream().collect(Collectors.toSet());

        // 获取所有歌曲的标签
        Map<Integer, Set<Integer>> songTags = getSongTags();
        Map<Pair<Integer, Integer>, Double> similarities = new HashMap<>();

        for (Map.Entry<Integer, Set<Integer>> entry2 : songTags.entrySet()) {

            double similarity = cosineSimilarity(tgs, entry2.getValue());
            similarities.put(Pair.of(songId, entry2.getKey()), similarity);
        }



        for (Map.Entry<Pair<Integer, Integer>, Double> entry : similarities.entrySet()) {

//            Similarity similarity = new Similarity();
//            similarity.setSongaId(entry.getKey().getFirst());
//            similarity.setSongbId(entry.getKey().getSecond());
//            similarity.setSimilarity(entry.getValue());
//            similarityMapper.insert(similarity);

            System.out.println(entry.getKey().getFirst()+" "+entry.getKey().getSecond()+" "+entry.getValue());
        }


    }

    @Override
    public void start(){
        calculateAndStoreSimilarities();
    }
}
